﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Reflection;

namespace Weka
{
    public abstract class Deserliser
    {
        private Dictionary<byte, KeyValueListPair> _cachedTypeDeserlisers = new Dictionary<byte, KeyValueListPair>(0);
        public object FromData(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
                return FromData(ms);
        }

        public object FromData(Stream stream)
        {
            return FromData(new StreamReada(stream));//TODO make generic
        }

        private object FromData(StreamReada streamReader)
        {
            byte messageId = (byte)streamReader.ReadByte();
            Key key = new Key(streamReader);
            KeyValueListPair b;
            ObjectDeserialiserProvider objectDeserialiserProvider;
            if (ObjectDeserialiserProviderCreator.TryGetValue(_cachedTypeDeserlisers, messageId, key, out b))
            {
                objectDeserialiserProvider = b.ObjectDeserialiserProvider;
            }
            else
            {
                var tds = new Dictionary<byte, KeyValueListPair>(_cachedTypeDeserlisers);
                ObjectDeserialiserProviderCreator qa = new ObjectDeserialiserProviderCreator(this, tds, key, messageId);

                objectDeserialiserProvider = qa.GetObjectDeserialiserProvider();
                Interlocked.Exchange(ref _cachedTypeDeserlisers, tds);
            }

            return objectDeserialiserProvider.Deserialise(streamReader);
        }


        internal static ObjectDeserialiserProvider<TM> GetObjectDeserialiserProvider<TM>(Dictionary<Type, ObjectDeserialiserProvider> cachedTypeSerlisers)
            where TM : new()
        {
            return (ObjectDeserialiserProvider<TM>)cachedTypeSerlisers[typeof(TM)];
        }


        public virtual Type GetMessageType(byte messageId)
        {
            foreach (var t in GetType().Assembly.GetTypes())
            {
                var misa = t.GetCustomAttributes(typeof(MessageIdAttribute), false);
                if (misa.Length == 1 && ((MessageIdAttribute)misa[0]).Id == messageId) return t;
            }
            return null;
        }

    }

    internal class DoNothingMessageReplacement { }
}
